home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Basic Source Code
/
Visual Basic Source Code.iso
/
vbsource
/
vbdatabs
/
ustring.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-31
|
17KB
|
608 lines
// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- //
// C++ Source Code File Name: ustring.cpp
// Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
// Produced By: Doug Gaer
// File Creation Date: 11/29/1996
// Date Last Modified: 03/31/1999
// Copyright (c) 1997 Douglas M. Gaer
// ----------------------------------------------------------- //
// ------------- Program Description and Details ------------- //
// ----------------------------------------------------------- //
/*
The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
All those who put this code or its derivatives in a commercial
product MUST mention this copyright in their documentation for
users of the products in which this code or its derivative
classes are used. Otherwise, you have the freedom to redistribute
verbatim copies of this source code, adapt it to your specific
needs, or improve the code and release your improvements to the
public provided that the modified files carry prominent notices
stating that you changed the files and the date of any change.
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
CORRECTION.
The UString class is a user-defined string class used to create
and manipulate non null-terminated resizable, variable-length
strings of binary data. UString objects are implemented as a
concrete data type, just like the built-in data types: char,
int, long, float, and double. The UString class supports string
concatenation, find, fill, and sub-string creation.
*/
// ----------------------------------------------------------- //
#include <ctype.h>
#include "ustring.h"
StrData StrData::Null_Ptr;
void *StrData::operator new(size_t StrSize, unsigned Bytes)
// Overloaded new operator used to allocate memory for the size
// of a StrData object plus number of bytes that represent the
// length of the string's data. The memory for the string is
// allocated as an array of characters. It is the responsibility
// of the UString class to keep track of the string's length.
// The UString class must store the string data immediately following
// the reference count. A null pointer object will be statically
// allocated when a new StrData object is constructed. Null strings
// will always point to the null pointer object.
{
// StrSize already accounts for one character
void *ptr = new char[StrSize + Bytes - 1];
if(!ptr) { // If allocation fails reference Null_Ptr
ptr = &Null_Ptr;
((StrData *)ptr)->RefCount++;
}
return ptr;
}
void StrData::operator delete(void *ptr)
// The delete operator is overloaded so that
// both the string data the reference count
// are deleted.
{
delete[] (char *)ptr;
}
int UString::Alloc(unsigned Bytes, int GB)
{
DataPtr = new(Bytes) StrData;
TextPtr = DataPtr->Data;
Len = 0;
if (IsNull()) { // Could not allocate memory for string
DimLen = 1;
GrowBy = 0;
return 0;
}
else {
DimLen = Bytes;
GrowBy = GB;
return 1;
}
}
void UString::Bind(const UString &s)
{
// Bind DataPtr to the same that s is bound to
DataPtr = s.DataPtr;
DataPtr->RefCount++;
}
void UString::UnBind()
{
DataPtr->RefCount--;
// Make sure RefCount is a non-zero value
if(DataPtr == &StrData::Null_Ptr && DataPtr->RefCount == 0)
DataPtr->RefCount = 1;
if(DataPtr->RefCount == 0) delete DataPtr;
}
void UString::NewBinding(const UString &s)
{
// Unbind string from DataPtr that holds it, and
// bind it to the DataPtr shared by s
if(DataPtr != s.DataPtr) {
UnBind();
Bind(s);
}
}
UString::UString(const char *s, unsigned Bytes, int GB)
{
if(Alloc(Bytes, GB)) CopyN(s, Bytes);
}
UString::UString(const char *s, int GB)
{
unsigned StringLen = strlen(s);
unsigned DimensionLen = StringLen;
if(GB) { // Compute next highest multiple of GB
unsigned AddValue = (DimensionLen % GB) ? GB : 0;
DimensionLen = (DimensionLen / GB) * GB + AddValue;
}
if(Alloc(DimensionLen, GB)) CopyN(s, StringLen);
}
UString::UString(const UString &s, unsigned Offset, unsigned Bytes, int GB)
// A constructor used to create a subset of this string.
{
Bind(s);
// Keep offset and length in range
if(Offset > s.Len-1) Offset = s.Len - 1;
if(Bytes + Offset > s.Len) Bytes = s.Len - Offset;
// Set max and logical bounds of the substring
DimLen = Bytes;
Len = Bytes;
GrowBy = GB;
TextPtr = s.TextPtr + Offset; // Compute starting text element
}
UString::UString(const UString &s)
{
Bind(s);
Len = s.Len;
DimLen = s.DimLen;
GrowBy = s.GrowBy;
TextPtr = s.TextPtr;
}
UString::~UString()
{
UnBind();
}
UString &UString::operator=(const UString &s)
{
if(this != &s) {
NewBinding(s);
Len = s.Len;
DimLen = s.DimLen;
GrowBy = s.GrowBy;
TextPtr = s.TextPtr;
}
return *this;
}
unsigned UString::InsReplAt(unsigned Pos,
const char *s, unsigned Bytes, int Ins)
{
unsigned Room, Needed, AddVal;
if(Ins) {
Room = DimLen - Len;
if(Bytes > Room && GrowBy != 0) {
Needed = (Bytes - Room);
AddVal = (Needed % GrowBy) ? GrowBy : 0;
Needed = (Needed / GrowBy) * GrowBy + AddVal;
Grow_By(Needed);
}
}
if (!EnsureUnique()) return 0; // Can't update
if (Pos >= Len) Pos = Len; // Don't allow gaps
if(Ins) { // Keep things in range. May have to truncate
if(Bytes > DimLen - Len) Bytes = DimLen - Len;
if(Pos < Len) {
// Make room in the middle for inserted data
memmove(TextPtr+Pos+Bytes, TextPtr+Pos, Len-Pos);
}
}
else {
if(Bytes > DimLen - Pos) Bytes = DimLen -Pos;
}
// Copy in source, compute final length
memmove(TextPtr+Pos, s, Bytes);
if(Ins) {
Len += Bytes;
}
else {
if((Pos+Bytes) > Len) Len = Pos+Bytes;
}
return Bytes;
}
int UString::Realloc(unsigned NewDimLen, int Keep)
{
if(GrowBy == 0) return 0;
StrData *NewStrData = new(NewDimLen) StrData;
if(NewStrData == &StrData::Null_Ptr) return 0;
if(Keep) { // Copy old data into new space.
if(NewDimLen < Len) Len = NewDimLen;
memmove(NewStrData->Data, TextPtr, Len);
}
else { // Do not keep old data
Len = 0;
}
UnBind(); // Unbind from old data
DataPtr = NewStrData; // Bind to new Data
TextPtr = DataPtr->Data; // Point to starting text
DimLen = NewDimLen; // Record new allocated length
return 1;
}
int UString::EnsureUnique()
{
if(!IsUnique()) {
// Create a unique clone of this string
UString buf(DimLen, GrowBy);
buf.CopyN(TextPtr, Len);
if(buf.IsNull()) return 0; // Could not copy
NewBinding(buf); // Bind to copy
TextPtr = buf.TextPtr; // Initialize starting text element
}
return 1;
}
void UString::SetLength(unsigned Bytes)
{
if(Bytes > DimLen) Bytes = DimLen;
Len = Bytes;
}
void UString::CopyN(const char *s, unsigned Bytes)
{
Len = 0; InsReplAt(0, s, Bytes);
}
void UString::Copy(const char *s)
{
CopyN(s, strlen(s));
}
void UString::Copy(const UString &s)
{
CopyN(s.TextPtr, s.Len);
}
unsigned UString::Find(char *s, unsigned Offset)
// Returns index of first occurrence of pattern char *s
// Returns 0xffff if pattern not found
{
char *Start = TextPtr + Offset; // Start of string data
char *Next = Start; // Next string element
char *Pattern = s; // Next pattern element
unsigned i = Offset; // Next string element index
while(i < Len && *Pattern) {
if (*Next == *Pattern) {
Pattern++;
if(*Pattern == 0) return i; // Pattern was found
Next++;
}
else {
i++;
Start++;
Next